import {computed, createComponent, getCurrentInstance, onBeforeUnmount, provide, reactive} from "@vue/composition-api";
import './vue-flow-editor.scss'
import {useCanvasProps, useEditorCommander, useEditorStyles, VueFlowEditorProvider} from "@/editor/editor";
import {formatNodeModel, suffixSize} from "@/utils/utils";

export default createComponent({
    name: 'vue-flow-editor',
    props: {
        data: {type: Object},                                                               // 渲染的数据
        grid: {type: [Boolean, Object], default: true},                                     // 是否需要网格
        miniMap: {type: [Boolean, Object], default: false},                                  // 是否需要缩略图
        disabledDragEdge: {type: Boolean},                                                  // 禁用拖拽连线功能
        disabledUndo: {type: Boolean},                                                      // 禁用撤销以及重做功能
        editorTitle: {type: String},                                                        // 编辑器标题

        height: {type: [String, Number], default: '100%'},                                  // 画布高度
        toolbarHeight: {type: [String, Number], default: '56'},                             // 顶部工具栏高度
        menuWidth: {type: [String, Number], default: '250'},                                // 左侧菜单栏高度
        modelWidth: {type: [Number, String], default: '500px'},                             // model 弹框的宽度

        onRef: {type: Function},                                                            // 获取引用函数
        toolbarButtonHandler: {type: Function},                                             // 工具栏按钮格式化函数
        loading: {type: Boolean},                                                           // 是否开启编辑器的loading状态

        multipleSelect: {type: Boolean, default: true},                                     // 是否可以多选

        beforeDelete: {type: Function},                                                     // 删除前校验
        afterDelete: {type: Function},                                                      // 删除后动作
        beforeAdd: {type: Function},                                                        // 添加前校验
        afterAdd: {type: Function},                                                         // 添加后动作

        activityConfig: {type: Object},                                         // 注册活动节点
    },
    setup(props, context) {

        const styles = useEditorStyles(props)
        const canvasProps = useCanvasProps(props)
        const modelBodyStyle = computed(() => ({
            width: suffixSize(props.modelWidth)
        }))
        const editorState = reactive({
            graph: null as any,                                         // graph 对象，canvas组件挂载初始化完毕会给这个属性赋值
            canvasProps,                                                // 传给canvas组件的属性，同时可以修改
            props,                                                      // 当前组件接收得到的属性，供子组件通过inject获取
            canvasKey: 0,                                               // canvas组件的key，以刷新canvas组件
            showModel: false,                                           // 详情对话框是否显示
            showPreview: false,                                         // 预览对话框显示
            data: null,
            refreshCanvas: () => {                                      // 刷新canvas组件
                editorState.canvasKey++
            },
            setGraph: (graph) => {
                editorState.graph = graph
                commander.init(graph)

                graph.on('node:dblclick', (e) => {
                    context.emit('dblclick-node', e)
                })
                graph.on('edge:dblclick', (e) => {
                    context.emit('dblclick-edge', e)
                })
                graph.on('select-change', (e) => {
                    context.emit('select-change', e)
                })
            }
        })
        const commander = useEditorCommander(editorState)

        const provideContext = {
            props,
            editorState,
            commander,
            openModel: () => {
                editorState.showModel = true
            },
            closeModel: () => {
                editorState.showModel = false
            },
            updateModel: (model) => {
                formatNodeModel(model, props.activityConfig)
                commander.commands.update(model)
            },
            openPreview: () => {
                editorState.data = editorState.graph.save()
                editorState.showPreview = true
            },
            read: (data) => {
                if (!!editorState.graph) {
                    editorState.graph.read(data)
                } else {
                    console.warn('graph is not initialized')
                }
            }
        }
        provide(VueFlowEditorProvider, provideContext)

        if (!!props.onRef) {
            props.onRef(provideContext)
        }

        const ctx = getCurrentInstance()
        Object.assign(ctx, provideContext)

        onBeforeUnmount(() => {
            commander.destroy()
            if (!!props.onRef) {
                props.onRef(null)
            }
        })

        return () => (
            <div class="vue-flow-editor" style={styles.value.root} v-loading={props.loading}>
                <div class="vue-flow-editor-left" style={styles.value.left}>
                    <vue-flow-editor-menu>
                        {!!context.slots.menu && context.slots.menu()}
                    </vue-flow-editor-menu>
                </div>
                <div class="vue-flow-editor-right">
                    <vue-flow-editor-toolbar style={styles.value.toolbar} canvasProps={canvasProps} toolbarButtonHandler={props.toolbarButtonHandler}>
                        {!!context.slots.toolbar && context.slots.toolbar()}
                    </vue-flow-editor-toolbar>
                    <vue-flow-editor-canvas {...{props: canvasProps}} key={String(editorState.canvasKey) + String(props.multipleSelect) + String(props.disabledDragEdge)}/>
                </div>
                <transition name="vue-flow-editor-transition">
                    <div class="vue-flow-editor-model" v-show={editorState.showModel}>
                        <div class="vue-flow-editor-model-body" style={modelBodyStyle.value}>
                            <div class="vue-flow-editor-model-head" style={styles.value.toolbar}>
                                <i class="el-icon-close" onClick={provideContext.closeModel}/>
                            </div>
                            <div class="vue-flow-editor-model-content">
                                {!!context.slots.model && context.slots.model()}
                            </div>
                            {
                                !!context.slots.foot && (
                                    <div class="vue-flow-editor-model-foot">
                                        {context.slots.foot()}
                                    </div>
                                )
                            }
                        </div>
                    </div>
                </transition>

                <vue-flow-editor-preview value={editorState.showPreview} onInput={val => editorState.showPreview = val} data={editorState.data}/>
            </div>
        )
    },

})
